//--------------------------------------------------------------------------------
// This file is a portion of the PracticeEngine Rendering Engine.  It is distributed
// under the MIT License, available in the root of this distribution and 
// at the following URL:
//
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright (c) Ferdinand Li 
//--------------------------------------------------------------------------------
#pragma once
#include "IRenderer.h"
#include <d3d11.h>
#include "PEMath.h"

namespace PracEng
{
	class DX11Renderer : public IRenderer
	{
	public:
		DX11Renderer(HWND hWnd, INT width, INT height) :m_hWnd(hWnd), m_BackbufferWidth(width), m_BackbufferHeight(height)
		{};
		virtual ~DX11Renderer(){};

		virtual void Initialize();
		virtual void Exit();
		virtual void Tick();
		
		virtual void Present();

		// create render target view
		HRESULT CreateRTView(ID3D11Resource* rt, const D3D11_RENDER_TARGET_VIEW_DESC* des, ID3D11RenderTargetView** RTV);
		// clear render target view
		inline void ClearRTView(ID3D11RenderTargetView* pRTView, float ClearColors[4]) { m_pDeviceContext->ClearRenderTargetView(pRTView, ClearColors); }
		// create depth stencil view
		HRESULT CreateDSView(ID3D11Resource* rt, const D3D11_DEPTH_STENCIL_VIEW_DESC* des, ID3D11DepthStencilView** DSV);
		// create shader resource view
		HRESULT CreateSRView(ID3D11Resource* rt, const D3D11_SHADER_RESOURCE_VIEW_DESC* des, ID3D11ShaderResourceView** SRV);
		// create texture2D
		HRESULT CreateTexture2D(const D3D11_TEXTURE2D_DESC* pDtd, const D3D11_SUBRESOURCE_DATA* pSubDat, ID3D11Texture2D** pTex2D);

		// get depth stencil state
		inline void GetDSState(ID3D11DepthStencilState **ppDepthStencilState, UINT* nPrevStencil) { m_pDeviceContext->OMGetDepthStencilState(ppDepthStencilState, nPrevStencil); }
		// set depth stencil state
		inline void SetDSState(ID3D11DepthStencilState *ppDepthStencilState, UINT nPrevStencil) { m_pDeviceContext->OMSetDepthStencilState(ppDepthStencilState, nPrevStencil); }
		// set pixel shader sampler
		inline void PSSetSampler(ID3D11SamplerState** Sampler) { m_pDeviceContext->PSSetSamplers(0, 1, Sampler); }
		inline void SetBlendState(ID3D11BlendState* pBlendState, FLOAT pBlendFactor[4], UINT SampleMask){ m_pDeviceContext->OMSetBlendState(pBlendState, pBlendFactor, SampleMask); }
		// get blend state
		inline void GetBlendState(ID3D11BlendState** pBlendState, FLOAT pBlendFactor[4], UINT* SampleMask){ m_pDeviceContext->OMGetBlendState(pBlendState, pBlendFactor, SampleMask); }
		// set rasterizer state
		inline void SetRSState(ID3D11RasterizerState* RasterState){ m_pDeviceContext->RSSetState(RasterState); }
		// get rasterizer state
		inline void GetRSState(ID3D11RasterizerState** pPrevRSState){ m_pDeviceContext->RSGetState(pPrevRSState); }

		// get D3D11 Device
		ID3D11Device* GetDevice() const;
		// get D3D11 immediate DeviceContext
		ID3D11DeviceContext* GetDeviceContext() const;
		// get IDXGIFactory
		IDXGIFactory* GetFactory() const;
		// get Current Feature Level
		D3D_FEATURE_LEVEL GetCurrentFeatureLevel() const;
		//
		UINT GetCurrentDeviceFlags() const;
		//
		D3D_DRIVER_TYPE GetCurrentDriverType() const;
		//
		ID3D11RenderTargetView* GetRenderTargetView() const;

		
		/** Utility Function*/
		INT LoadShader(LPCWSTR FileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob **ppCode);

		//get current back buffer width
		inline UINT GetBackBufferWidth(){ return m_BackbufferWidth; }
		inline UINT GetBackBufferHeight(){ return m_BackbufferHeight; }

	private:
		ID3D11Device* m_pDevice;
		ID3D11DeviceContext* m_pDeviceContext;
		IDXGISwapChain* m_pSwapChain;
		D3D_FEATURE_LEVEL m_CurrfeatureLevel;
		D3D_DRIVER_TYPE m_CurrDriverType;
		UINT m_CurrDeviceFlags;
		HWND m_hWnd;
		UINT m_BackbufferWidth;
		UINT m_BackbufferHeight;

		ID3D11RenderTargetView* m_pRenderTargetView;
	};
}
